package ru.tapublog.lib.samsungwallet.api.model;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class Ticket {

	private static final String DEFAULT_VERSION = "1.1";
	
	private String version;
	private String serial;
	private String skinId;
	private boolean storable = true;
	private Date validUntil;
	private Set<String> keywords;

	private Set<AbstractViewElement> viewElements;

	// Alerts
	private Set<AbstractAlert> alerts;

	// Partners
	private Set<Partner> partners;

	public Ticket(String version, String serial, String skinId) {
		setVersion(version);
		setSerial(serial);
		setSkinId(skinId);
	}

	public Ticket(String serial, String skinId) {
		this(DEFAULT_VERSION, serial, skinId);
	}

	public boolean addPartner(Partner partner) {
		if (partners == null)
			partners = new HashSet<Partner>();
		return partners.add(partner);
	}

	public boolean removePartner(Partner partner) {
		if (partners == null)
			return false;
		return partners.remove(partner);
	}

	public Set<Partner> getPartners() {
		if (partners == null)
			return new HashSet<Partner>();
		return new HashSet<Partner>(partners);
	}

	private boolean containsDateAlert() {
		for (AbstractAlert alert : alerts) {
			if (alert instanceof DateAlert)
				return true;
		}
		return false;
	}

	private boolean addDateAlert(DateAlert alert) {
		if (!alerts.isEmpty() && !containsDateAlert())
			throw new IllegalStateException(
					"There are Geofence Alerts already present in the ticket. You cannot have both Date and Geofence Alerts in one ticket.");
		alerts.clear();
		return alerts.add(alert);
	}

	private boolean addGeofenceAlert(GeofenceAlert alert) {
		if (containsDateAlert())
			throw new IllegalStateException(
					"There is Date Alert already present in the ticket. You cannot have both Date and Geofence Alerts in one ticket.");

		if (alerts.size() == 20)
			throw new IllegalStateException(
					"There are already 20 Geofence Alerts in the ticket. No more possible.");

		return alerts.add(alert);
	}

	public boolean addAlert(AbstractAlert alert) throws IllegalStateException {
		if (alerts == null)
			alerts = new HashSet<AbstractAlert>();
		if (alert instanceof DateAlert)
			return addDateAlert((DateAlert)alert);
		else
			return addGeofenceAlert((GeofenceAlert)alert);
	}

	public boolean removeAlert(GeofenceAlert alert) {
		if (alerts == null)
			return false;
		return alerts.remove(alert);
	}

	public Set<AbstractAlert> getAlerts() {
		if (alerts == null)
			return new HashSet<AbstractAlert>();
		return new HashSet<AbstractAlert>(alerts);
	}

	public boolean addKeyword(String keyword) {
		if (this.keywords == null)
			this.keywords = new HashSet<String>();
		return this.keywords.add(keyword);
	}

	public boolean removeKeyword(String keyword) {
		if (this.keywords == null)
			return false;
		return this.keywords.remove(keyword);
	}

	public Set<String> getKeywords() {
		if (this.keywords == null)
			return new HashSet<String>();
		return new HashSet<String>(this.keywords);
	}

	public boolean addViewElement(AbstractViewElement viewElement) {
		if (viewElements == null)
			viewElements = new HashSet<AbstractViewElement>();
		return viewElements.add(viewElement);
	}

	public boolean removeViewElement(AbstractViewElement viewElement) {
		if (viewElements == null)
			return false;
		return viewElements.remove(viewElement);
	}

	public Set<AbstractViewElement> getViewElements() {
		if (viewElements == null)
			return new HashSet<AbstractViewElement>();
		return new HashSet<AbstractViewElement>(viewElements);
	}

	public Date getValidUntil() {
		return this.validUntil;
	}

	private void setValidUntil(Date validUntil) {
		this.validUntil = validUntil;
	}

	public String getVersion() {
		return this.version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getSerial() {
		return this.serial;
	}

	public void setSerial(String serial) {
		this.serial = serial;
	}

	public String getSkinId() {
		return this.skinId;
	}

	public void setSkinId(String skinId) {
		this.skinId = skinId;
	}

	public boolean isStoreOnServerEnabled() {
		return this.storable;
	}

	public void disableStoreOnServer(Date validUntil) {
		this.storable = false;
		setValidUntil(validUntil);
	}

	public void enableStoreOnServer() {
		this.storable = true;
		this.validUntil = null;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((this.serial == null) ? 0 : this.serial.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Ticket other = (Ticket) obj;
		if (this.serial == null) {
			if (other.serial != null)
				return false;
		} else if (!this.serial.equals(other.serial))
			return false;
		return true;
	}

}
